<template>
  <div ref="container">
    <div class="assess">
      <div id="info">
        逃离密室，你在一个陌生的房间中醒来，房间中空无一人，门与窗都被紧锁，你需要找到钥匙，然后逃出房间
      </div>
      <canvas class="c"  @dblclick="getKey" ref="ThreeJS"></canvas>
    </div>
    <div class="dialog " v-if="showkey">
      <div class="active-key animista1">
        <el-image :src="require('./../../../assets/key.png')"></el-image>
        <div class="active-desc">恭喜您找到了钥匙，成功通关</div>
        <el-button size="mini" @click="nextAss()">结束,下一项</el-button>
      </div>
    </div>
  </div>
</template>

<script>
import * as THREE from "three";
window.THREE = THREE;
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader";

export default {
  data() {
    return {
      showkey: false,

      scene: null, // 场景（布景空间）
      camera: null, // 相机（拍摄镜头）
      cameraPole: null,
      renderer: null, // 渲染器（类似电脑屏幕）
      canvas: null,
      canvasW: 0,
      canvasH: 0, // 画布宽高
      stats: null, // 性能监视器
      cameraParam: {
        fov: 40, // 视角 field of view
        aspect: 2, // 相机拍摄面的长宽比 aspece ratio
        near: 1, // 近裁剪面
        far: 1000, // 远裁剪面
      },
      floor: null,
      wall_back: null,
      wall_left: null,
      wall_right: null,
      plight: null,
      spotLight: null,
      events: {
        raycaster: new THREE.Raycaster(),
        pickedObject: null,
        pickedObjectSavedColor: 0,
        pickPosition: new THREE.Vector2(0, 0),
      },


      // 所有的物体
      cbbox: null,

    };
  },
  created() {
    this.canvasW = window.innerWidth;
    this.canvasH = window.innerHeight;
    // 初始化设置宽高比
    this.cameraParam.aspect = this.canvasW / this.canvasH;
  },
  mounted() {
    this.start();
  },
  methods: {
    nextAss: function () {
      this.$emit('nextAss')
    },
    getKey: function(){
      this.showkey = true;
    },

    start() {
      // 初始化三要素
      this.initMain();
      // 启用渲染
      this.render();
    },
    initMain() {
      // 初始化三要素
      this.initScene();
      this.initCamera();
      this.initRenderer();
      // 添加环境光
      this.addLight();
      // 性能监视器
      this.initStats();
      // 所有物体都放在这儿
      this.addObject();
      this.addModelofObj();

      this.addHelper();
      this.addOrbitControls();

      this.addEventHandler();
    },
    // 动画的性能监视器
    initStats: function () {
      this.stats = new Stats();
      const statsDom = this.stats.domElement;
      statsDom.style.position = "fixed";
      statsDom.style.bottom = "0";
      statsDom.style.right = "0";
      statsDom.style.left = "unset";
      this.$refs.container.appendChild(statsDom);
    },
    initScene() {
      // 创建场景
      this.scene = new THREE.Scene();
    },
    initCamera() {
      // 创建透视摄像头
      const cP = this.cameraParam;
      this.camera = new THREE.PerspectiveCamera(
        cP.fov,
        cP.aspect,
        cP.near,
        cP.far
      );
      this.camera.position.set(50, 80, 80);
      this.camera.lookAt(10, 0, 0);
      this.scene.add(this.camera);
    },
    initRenderer() {
      // 渲染器
      this.canvas = this.$refs.ThreeJS;
      this.renderer = new THREE.WebGLRenderer({
        canvas: this.canvas,
        antialias: true, //是否开启反锯齿，设置为true开启反锯齿。
        alpha: false, //是否可以设置背景色透明。
        logarithmicDepthBuffer: true, //模型的重叠部位便不停的闪烁起来。这便是Z-Fighting问题，为解决这个问题，我们可以采用该种方法
      });
      this.renderer.shadowMap.enabled = true; // 开启阴影
      this.renderer.setClearColor(0xa0877d);
      this.renderer.clearColor();
    },
    /**
     * 光源
     */
    addLight() {
      // 点光源
      this.plight = new THREE.PointLight(0xffffff, 1, 200);
      this.plight.position.set(20, 30, 20);
      this.plight.castShadow = true;
      this.scene.add(this.plight);

      // 聚光灯
      this.spotLight = new THREE.SpotLight(
        0xffffff,
        0.5,
        200,
        (Math.PI / 180) * 45,
        0,
        0
      );
      this.spotLight.position.set(0, 90, 0);
      this.spotLight.castShadow = true;
      this.scene.add(this.spotLight);
    },

    render() {
      // 启动动画
      this.renderer.render(this.scene, this.camera);
      // 动态监听窗口尺寸变化
      if (this.resizeRendererToDisplaySize(this.renderer)) {
        const canvas = this.renderer.domElement;
        this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
        this.camera.updateProjectionMatrix();
      }
      this.stats.update();
      requestAnimationFrame(this.render.bind(this)); // 类似循环
    },

    resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement;
      this.canvasW = window.innerWidth;
      this.canvasH = window.innerHeight;
      const needResize =
        canvas.width !== this.canvasW || canvas.height !== this.canvasH;
      if (needResize) {
        this.renderer.setSize(this.canvasW, this.canvasH, false);
      }
      return needResize;
    },

    // 将所有创建的物体实例都放到这里
    addObject() {
      this.createFloor();
      this.createBoxWithTextures();
      this.createWall();
    },
    // 添加地面
    createFloor() {
      // 贴图
      const texturloader = new THREE.TextureLoader().load(
        "./../../static/textures/hardwood2_diffuse.jpg"
      );
      this.floor = new THREE.Mesh(
        new THREE.BoxGeometry(100, 2, 100),
        new THREE.MeshStandardMaterial({ map: texturloader })
      );
      this.floor.position.y = -1;
      this.floor.receiveShadow = true;
      this.scene.add(this.floor);
    },
    /**
     * 给墙添加材质
     */
    createWall() {
      // 贴图
      const texturloader = new THREE.TextureLoader().load(
        "./../../static/textures/wall.png"
      );

      // 贴图
      const cb = new THREE.Mesh(
        new THREE.BoxGeometry(2, 30, 100),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb.position.y = 15;
      cb.position.x = -50;
      this.scene.add(cb);

      const cb2 = new THREE.Mesh(
        new THREE.BoxGeometry(2, 30, 100),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb2.position.y = 15;
      cb2.position.x = 50;
      this.scene.add(cb2);

      const cb3 = new THREE.Mesh(
        new THREE.BoxGeometry(48, 30, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb3.position.y = 15;
      cb3.position.x = -26;
      cb3.position.z = -50;
      this.scene.add(cb3);

      const texturloader2 = new THREE.TextureLoader().load(
        "./../../static/textures/wall-litter.png"
      );
      const cb4 = new THREE.Mesh(
        new THREE.BoxGeometry(28, 30, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader2,
        })
      );
      cb4.position.y = 15;
      cb4.position.x = 36;
      cb4.position.z = -50;
      this.scene.add(cb4);

      const cb5 = new THREE.Mesh(
        new THREE.BoxGeometry(24, 10, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader2,
        })
      );
      cb5.position.y = 5;
      cb5.position.x = 10;
      cb5.position.z = -50;
      this.scene.add(cb5);

      const texturloader3 = new THREE.TextureLoader().load(
        "./../../static/textures/wall-l.png"
      );
      const cb6 = new THREE.Mesh(
        new THREE.BoxGeometry(24, 2, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader3,
        })
      );
      cb6.position.y = 29;
      cb6.position.x = 10;
      cb6.position.z = -50;
      this.scene.add(cb6);

      const cb7 = new THREE.Mesh(
        new THREE.BoxGeometry(70, 30, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb7.position.y = 15;
      cb7.position.x = -15;
      cb7.position.z = 50;
      this.scene.add(cb7);

      const cb8 = new THREE.Mesh(
        new THREE.BoxGeometry(14, 30, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb8.position.y = 15;
      cb8.position.x = 43;
      cb8.position.z = 50;
      this.scene.add(cb8);

      const cb9 = new THREE.Mesh(
        new THREE.BoxGeometry(16, 8, 2),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      cb9.position.y = 26;
      cb9.position.x = 28;
      cb9.position.z = 50;
      this.scene.add(cb9);
    },
    /**
     * 一个带贴图的箱子
     */
    createBoxWithTextures() {
      // 贴图
      const texturloader = new THREE.TextureLoader().load(
        "./../../static/textures/crate.gif"
      );

      this.cbbox = new THREE.Mesh(
        new THREE.BoxBufferGeometry(8, 8, 8),
        new THREE.MeshStandardMaterial({
          map: texturloader,
        })
      );
      this.cbbox.position.y = 4;
      this.cbbox.position.x = 12;
      this.cbbox.castShadow = true;

      this.scene.add(this.cbbox);
    },

    addHelper() {
      this.addAxesHelper();
      this.addPointLightHelper();
    },
    // 增加坐标轴
    addAxesHelper() {
      // xyz轴
      const axesHelper = new THREE.AxesHelper(20);
      this.scene.add(axesHelper);
    },
    // 光源
    addPointLightHelper() {
      const pointLightHelper = new THREE.PointLightHelper(this.plight);
      this.scene.add(pointLightHelper);
    },

    // 轨道控制器，相机,此时就可以控制相机
    addOrbitControls() {
      const orbitControls = new OrbitControls(this.camera, this.$refs.ThreeJS);
    },

    /**
     * 加载所有的内容
     */
    addModelofObj() {
      this.addObjOfFrame();
      this.addObjOfWindow();
      this.addObjOfTable();
    },
    /**
     * 相框
     */
    addObjOfFrame() {
      const texturloader = new THREE.TextureLoader().load(
        "./../../static/textures/char.png"
      );
      let photo = new THREE.Mesh(
        new THREE.PlaneGeometry(12, 8),
        new THREE.MeshStandardMaterial({
          map: texturloader,
          side: THREE.DoubleSide,
        })
      );
      photo.position.y = 20;
      photo.position.x = -10;
      photo.position.z = -48.8;
      this.scene.add(photo);
    },
    /**
     * 窗户
     */
    addObjOfWindow() {
      let that = this;
      const mtlloader = new MTLLoader();
      const loader = new OBJLoader();
      mtlloader.load("./../../static/window/file.mtl", function (mtl) {
        loader
          .setMaterials(mtl)
          .load("./../../static/window/file.obj", function (group) {
            group.position.y = 10;
            group.position.z = -50;
            group.position.x = 10;
            group.castShadow = true;
            group.scale.set(0.4, 0.3, 0.5);
            that.scene.add(group);
          });
      });
    },
    addObjOfTable() {
      let that = this;
      const mtlloader = new MTLLoader();
      const loader = new OBJLoader();
      mtlloader.load("./../../static/table/file.mtl", function (mtl) {
        loader
          .setMaterials(mtl)
          .load("./../../static/table/file.obj", function (group) {
            group.scale.set(0.015, 0.015, 0.015);
            group.position.z = -36;
            group.position.x = -30;
            group.castShadow = true;
            that.scene.add(group);
          });
      });
    },

    // 鼠标控制事件
    addEventHandler() {
      let x = 0,
        y = 0,
        width = 0,
        height = 0;
      // 鼠标移动事件
      this.renderer.domElement.addEventListener("mousemove", (event) => {
        x = event.offsetX;
        y = event.offsetY;
        width = this.renderer.domElement.offsetWidth;
        height = this.renderer.domElement.offsetHeight;
        this.events.pickPosition.x = (x / width) * 2 - 1;
        this.events.pickPosition.y = (-y * 2) / height + 1;
        // 初始化射线发射器
        this.events.raycaster.setFromCamera(
          this.events.pickPosition,
          this.camera
        );
        const intersectlist = this.events.raycaster.intersectObjects(
          this.scene.children
        );
      });

      // 鼠标点击事件
      this.renderer.domElement.addEventListener("click", (event) => {
        this.events.raycaster.setFromCamera(
          this.events.pickPosition,
          this.camera
        );
        const intersectlist = this.events.raycaster.intersectObjects(
          this.scene.children
        );
        if (intersectlist.length) {
          console.log('intersectlist length is ', intersectlist.length);
          let object = intersectlist[0];
          // this.showkey = true;
          if (object == this.cbbox) {
            console.log(12);
          }
          if (object == this.floor) {
            console.log("floor is clicked");
          }
        }
      });
    },
  },
};
</script>

<style scoped>
.c {
  width: 100%;
  height: 100%;
  display: block;
}

#info {
  position: absolute;
  top: 60px;
  width: 60%;
  margin: 0 auto;
  text-align: center;
  z-index: 100;
  font-size: 1.5em;
  display: block;
}

.dialog {
  position: absolute;
  top: 30%;
  left: 35%;
  margin: 0 auto;
  text-align: center;
  z-index: 100;
  font-size: 1.5em;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgb(80, 80, 80, .6);
  border-radius: 20px;
  padding: 60px 120px;
}


.animista1 {
  animation: scale-up-center 1.5s;
  -webkit-animation: scale-up-center 1.5s;
  /* Safari and Chrome */
}

@-webkit-keyframes scale-up-center {
  0% {
    -webkit-transform: scale(0.5);
    transform: scale(0.8);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

@keyframes scale-up-center {
  0% {
    -webkit-transform: scale(0.8);
    transform: scale(0.8);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

.active-key {
  /* box-shadow: 1px 1px 2px black,
    0 0 25px rgb(94, 94, 107),
    0 0 5px rgb(77, 77, 87); */
  border-radius: 20px;

}

.active-desc {
  font-size: 1.3em;
  font-weight: bold;
  color: #89ea84;
  padding-bottom: 20px;
}
</style>
